using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using XNAGuiLib.GuiLibAction;
using XNAGuiLib.GuiLibFrames;

namespace XNAGuiLib
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class InterfaceObject : DrawableGameComponent, IAction, IScrollable
    {

        #region Field - Sprite
        protected SpriteBatch _sprite;
        /// <summary>
        /// gets or sets the InterfaceManagers SpriteBatch
        /// </summary>
        public SpriteBatch Sprite
        {
            get
            {
                return _sprite;
            }
            set
            {
                _sprite = value;
            }
        }
        #endregion

        #region Field - Position
        protected Vector2 _position = Statics.ZeroVector2;
        /// <summary>
        /// gets or sets InterfaceObjects position on screen
        /// </summary>
        public Vector2 Position
        {
            get
            {
                return _position;
            }
            set
            {
                _position = value;

                foreach (TextObject obj in _textObjs)
                {
                    obj.Position = value + _relativePosition;
                }
                foreach (TextureObject obj in _textureObjs)
                {
                    obj.Position = value + _relativePosition;
                }
                foreach (InterfaceObject obj in _ios)
                {
                    obj.Position = value;
                }
                 
            }
        }
        #endregion


        #region Field - RelativePosition
        // accessor field for X-coordinate
        #region Field - X
        /// <summary>
        /// gets or sets x Position
        /// </summary>
        public float X
        {
            get
            {
                return _relativePosition.X;
            }
            set
            {
                _relativePosition = new Vector2(value, _relativePosition.Y);
            }
        }
        #endregion
        // accessor field for Y-coordinate
        #region Field - Y
        /// <summary>
        /// gets or sets y Position
        /// </summary>
        public float Y
        {
            get
            {
                return _relativePosition.Y;
            }
            set
            {
                _relativePosition = new Vector2(_relativePosition.X, value);
            }
        }
        #endregion
        // accessor and storage field for X/Y-coordinates
        #region Field - RelativePosition
        protected Vector2 _relativePosition = Statics.ZeroVector2;
        /// <summary>
        /// gets or sets InterfaceObjects relative position (when added in a different InterfaceObject)
        /// </summary>
        public Vector2 RelativePosition
        {
            get
            {
                return _relativePosition;
            }
            set
            {
                _relativePosition = value;

                foreach (TextObject obj in _textObjs)
                {
                    obj.Position = _position + value;
                }
                foreach (TextureObject obj in _textureObjs)
                {
                    obj.Position = _position + value;
                }
                foreach (InterfaceObject obj in _ios)
                {
                    obj.Position = _position + value;
                }
            }
        }
        #endregion
        #endregion

        #region Field - Bounds
        // accessor field for width value
        #region Field - Width
        /// <summary>
        /// gets or sets Width
        /// </summary>
        public float Width
        {
            get
            {
                return Bounds.X;
            }
            set
            {
                Bounds = new Vector2(value, Bounds.Y);
            }
        }
        #endregion
        // accessor field for height value
        #region Field - Height
        /// <summary>
        /// gets or sets Height
        /// </summary>
        public float Height
        {
            get
            {
                return Bounds.Y;
            }
            set
            {
                Bounds = new Vector2(Bounds.X, value);
            }
        }
        #endregion
        // accessor and storage field for height/width values
        #region Field - Bounds
        protected Vector2 _bounds;
        /// <summary>
        /// gets or sets the bounds (width and height) of this InterfaceObject
        /// </summary>
        public Vector2 Bounds
        {
            get
            {
                return _bounds;
            }
            set
            {
                //Vector2 scaling = _bounds / value;
                //Console.WriteLine(this._name + " scaling: " + scaling);
                _bounds = value;
            }
        }
        #endregion
        #endregion


        #region Field - Font
        protected SpriteFont _font;
        /// <summary>
        /// gets or sets the InterfaceObjects SpriteFont
        /// </summary>
        public SpriteFont Font
        {
            get
            {
                return _font;
            }
            set
            {
                _font = value;

                foreach (TextObject to in _textObjs)
                {
                    to.Font = value;
                }
            }
        }
        #endregion

        #region Field - TextColor
        protected Color _textcolor = Color.Black;
        /// <summary>
        /// gets or sets the InterfaceObjects TextColor
        /// </summary>
        public Color TextColor
        {
            get
            {
                return _textcolor;
            }
            set
            {
                _textcolor = value;

                foreach (TextObject textObj in _textObjs)
                {
                    textObj.TextColor = value;
                }
            }
        }
        #endregion

        #region Field - Title
        protected string _title;
        /// <summary>
        /// gets or sets the title of the Frame
        /// </summary>
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
            }
        }
        #endregion


        #region Field - TextureColor
        protected Color _texturecolor = Color.White;
        /// <summary>
        /// gets or sets the InterfaceObjects TextColor
        /// </summary>
        public Color TextureColor
        {
            get
            {
                return _texturecolor;
            }
            set
            {
                _texturecolor = value;

                foreach (TextureObject textureObj in _textureObjs)
                {
                    textureObj.Color = value;
                }
            }
        }
        #endregion

        #region Field - Parent
        protected InterfaceObject _parent;
        /// <summary>
        /// gets or sets the parent InterfaceObject (owner) of this InterfaceObject
        /// </summary>
        public InterfaceObject Parent
        {
            get
            {
                return _parent;
            }
            set
            {
                _parent = value;
            }
        }
        #endregion

        #region Field - Scale
        protected Vector2 _scale = new Vector2(1.0f, 1.0f);
        /// <summary>
        /// gets or sets the InterfaceObjects scale
        /// </summary>
        public Vector2 Scale
        {
            get
            {
                return _scale;
            }
            set
            {
                _scale = value;

                foreach (TextureObject textureObj in _textureObjs)
                {
                    textureObj.Scale = value;
                }

                foreach (TextObject textObj in _textObjs)
                {
                    textObj.Scale = value.X;
                }
            }
        }
        #endregion

        #region Field - Rotation
        protected float _rotation = 0.0f;
        /// <summary>
        /// gets or sets the InterfaceObjects drawind rotation
        /// </summary>
        public float Rotation
        {
            get
            {
                return _rotation;
            }
            set
            {
                _rotation = value;
            }
        }
        #endregion

        #region Field - Origin
        private Vector2 _origin = new Vector2(0.0f, 0.0f);
        /// <summary>
        /// gets the Origin of this InterfaceObject
        /// </summary>
        public Vector2 Origin
        {
            get
            {
                return _origin;
            }
        }
        #endregion

        #region Field - Effects
        protected SpriteEffects _effects = SpriteEffects.None;
        /// <summary>
        /// gets or sets the InterfaceObjects SpriteEffects
        /// </summary>
        public SpriteEffects Effects
        {
            get
            {
                return _effects;
            }
            set
            {
                _effects = value;
            }
        }
        #endregion

        #region Field - LayerDepth
        protected float _layerDepth = 1.0f;
        /// <summary>
        /// gets or sets the InterfaceObjects layer depth (between 0.0 and 1.0)
        /// </summary>
        public float LayerDepth
        {
            get
            {
                return _layerDepth;
            }
            set
            {
                _layerDepth = value;

                foreach (TextObject obj in _textObjs)
                {
                    obj.LayerDepth = value;
                }
                foreach (TextureObject obj in _textureObjs)
                {
                    obj.LayerDepth = value;
                }
                foreach (InterfaceObject obj in _ios)
                {
                    obj.LayerDepth = value;
                }
            }
        }
        #endregion

        #region Field - Name
        protected string _name = "";
        /// <summary>
        /// gets or sets the InterfaceObjects name
        /// </summary>
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
        #endregion

        #region Field - IsInitialized
        protected bool _initialized = false;
        /// <summary>
        /// gets if the InterfaceObject is successfully initialized and won't cause Exceptions because of missing Textures etc.
        /// </summary>
        public bool IsInitialized
        {
            get
            {
                return _initialized;
            }
        }
        #endregion

        #region Field - Visible
        public new bool Visible
        {
            get
            {
                return base.Visible;
            }
            set
            {
                base.Visible = value;

                foreach (InterfaceObject io in _ios)
                {
                    io.Visible = value;
                }
                foreach (TextureObject txo in _textureObjs)
                {
                    txo.Visible = value;
                }

                foreach (TextObject to in _textObjs)
                {
                    to.Visible = value;
                }
            }
        }

        #endregion

        #region Field - Focused
        protected bool _focused = false;
        /// <summary>
        /// gets or sets if this component is currently under focus
        /// </summary>
        public bool Focused
        {
            get
            {
                return _focused;
            }
            set
            {
                _focused = value;
            }
        }
        #endregion

        #region Field - IsMouseListening
        protected bool _isMouseListening;
        /// <summary>
        /// gets or sets wether the InterfaceObject is MouseListening or not
        /// </summary>
        public bool IsMouseListening
        {
            get
            {
                return _isMouseListening;
            }
            set
            {
                _isMouseListening = value;
            }
        }
        #endregion

        #region Field - IsKeyboardListening
        protected bool _isKeyboardListening;
        /// <summary>
        /// gets or sets wether the InterfaceObject is KeyboardListening or not
        /// </summary>
        public bool IsKeyboardListening
        {
            get
            {
                return _isKeyboardListening;
            }
            set
            {
                _isKeyboardListening = value;
            }
        }
        #endregion


        #region Field List - InterfaceObjects
        protected List<InterfaceObject> _ios = new List<InterfaceObject>(0);
        /// <summary>
        /// gets or sets the InterfaceObject List
        /// </summary>
        public List<InterfaceObject> InterfaceObjects
        {
            get
            {
                return _ios;
            }
            set
            {
                _ios = value;
            }
        }

        #endregion

        #region Field List - TextureObjs
        protected List<TextureObject> _textureObjs = new List<TextureObject>();
        /// <summary>
        /// gets TextureObject on index
        /// </summary>
        public TextureObject TextureObject(int index)
        {
            return _textureObjs[index];
        }
        #endregion

        #region Field List - TextObjs
        protected List<TextObject> _textObjs = new List<TextObject>();
        /// <summary>
        /// gets TextObject on index
        /// </summary>
        public TextObject TextObject(int index)
        {
            return _textObjs[index];
        }
        #endregion

        #region Field List - Actions
        protected List<Action> _actions = new List<Action>();
        /// <summary>
        /// gets ir sets the ActionList of this InterfaceObject
        /// </summary>
        public List<Action> Actions
        {
            get
            {
                return _actions;
            }
            set
            {
                _actions = value;
            }
        }
        /// <summary>
        /// gets the InterfaceAction on index
        /// </summary>
        /// <param name="index">the index to get from the list</param>
        /// <returns>InterfaceAction object on the given index</returns>
        public Action GetAction(int index)
        {
            return _actions[index];
        }
        #endregion



        #region Constructor - InterfaceObject(Game game, string name, Vector2 relPosition, bool visible) : base(game)
        public InterfaceObject(Game game, string name, Vector2 relPosition, bool visible)
            : base(game)
        {
            // set the name
            _name = name;
            // set the relativePosition
            _relativePosition = relPosition;
            // set if GameComponent should be visible
            Visible = visible;
        }
        #endregion


        #region Method - Add(...)
        //
        #region Method - Add(InterfaceObject item)
        public void Add(InterfaceObject item)
        {
            if (!_ios.Contains(item))
            {
                item.Parent = this;
                _ios.Add(item);
            }
            else
            {
                item.Parent = this;
                _ios[_ios.IndexOf(item)] = item;
            }

            if (Game.Components.Contains(this))
            {
                int baseIndex = Game.Components.IndexOf(this);
                if (baseIndex >= 0 && !Game.Components.Contains(item))
                    Game.Components.Insert(baseIndex + _ios.IndexOf(item), item);
            }

            foreach (InterfaceObject io in item._ios)
            {
                _ios.Add(io);
            }
        }
        #endregion

        #region Method - Add(TextureObject item)
        public void Add(TextureObject item)
        {
            _textureObjs.Add(item);
        }
        #endregion

        #region Method - Add(TextObject item)
        public void Add(TextObject item)
        {
            _textObjs.Add(item);
        }
        #endregion
        #endregion

        #region Method - Remove(...)
        //
        #region Method - Remove(InterfaceObject item)
        public void Remove(InterfaceObject item)
        {
            _ios.Remove(item);
        }
        #endregion

        #region Method - Remove(TextureObject item)
        public void Remove(TextureObject item)
        {
            _textureObjs.Remove(item);
        }
        #endregion

        #region Method - Remove(TextObject item)
        public void Remove(TextObject item)
        {
            _textObjs.Remove(item);
        }
        #endregion
        #endregion

        #region Method - InstallInterface()
        public void InstallInterface()
        {
            if (!Game.Components.Contains(this))
            {
                Game.Components.Add(this);

                
                foreach (InterfaceObject io in _ios)
                {
                    Game.Components.Remove(io);
                }

                int baseIndex = Game.Components.IndexOf(this);
                foreach (InterfaceObject io in _ios)
                {
                    if (!Game.Components.Contains(io))
                    {
                        Game.Components.Insert(baseIndex + _ios.IndexOf(io), io);
                        io.InstallInterface();
                    }
                }
            }
        }
        #endregion

        #region Method - InstallAction(Action action)
        public int InstallAction(Action action)
        {
            _actions.Add(action);
            return _actions.Count;
        }
        #endregion

        #region Method - SearchList(...)
        //
        #region Method - SearchList(TextureObject textureObject)
        public int SearchList(TextureObject textureObject)
        {
            for (int i = 0; i < _textureObjs.Count; i++)
            {
                if (_textureObjs[i].Name.CompareTo(textureObject.Name) == 0) return i;
            }

            return -1;
        }
        #endregion
        //
        #region Method - SearchList(TextObject textObject)
        public int SearchList(TextObject textObject)
        {
            for (int i = 0; i < _textObjs.Count; i++)
            {
                if (_textObjs[i].Name.CompareTo(textObject.Name) == 0) return i;
            }

            return -1;
        }
        #endregion
        #endregion

        #region Method - SearchTextureList(string name)
        public int SearchTextureList(string name)
        {
            for (int i = 0; i < _textureObjs.Count; i++)
            {
                if (_textureObjs[i].Name.CompareTo(name) == 0) return i;
            }

            return -1;
        }
        #endregion

        #region Method - SearchTextList(string name)
        public int SearchTextList(string name)
        {
            for (int i = 0; i < _textObjs.Count; i++)
            {
                if (_textObjs[i].Name.CompareTo(name) == 0) return i;
            }

            return -1;
        }
        #endregion

        #region Method - SearchActionList(int index)
        public Action SearchActionList(int index)
        {
            return _actions[index];
        }
        #endregion

        #region Method - IsInIos(InterfaceObject io)
        public bool IsInIos(InterfaceObject io)
        {
            bool ret = _ios.Contains(io);
            if(!ret)
            {
                foreach (InterfaceObject iob in _ios)
                {
                    ret = iob.IsInIos(io);
                    if (ret) break;
                }
            }
            return ret;
        }
        #endregion

        #region Method - ResolveTotalRectangle()
        public Rectangle ResolveTotalRectangle()
        {
            Rectangle ret = new Rectangle((int)_relativePosition.X, (int)_relativePosition.Y, (int)_bounds.X, (int)_bounds.Y);
            if (_parent != null)
            {
                ret = new Rectangle((int)(ret.X + _parent.ResolveTotalRectangle().X), (int)(ret.Y + _parent.ResolveTotalRectangle().Y), (int)ret.Width, (int)ret.Height);
                return ret;
            }
            else return new Rectangle(ret.X + (int)_position.X, ret.Y + (int)_position.Y, ret.Width, ret.Height);
        }
        #endregion

        #region Method - ResolveParentPath()
        public string ResolveParentPath()
        {
            string ret = _name + " -> ";
            if (_parent != null)
            {
                ret += _parent.ResolveParentPath();
                return ret;
            }
            else return _name + " is root!";
        }
        #endregion

        #region Method - GetBounds()
        public Rectangle GetBounds()
        {
            int x = (int)_relativePosition.X + (int)_position.X;
            int y = (int)_relativePosition.Y + (int)_position.Y;
            int width = (int)_bounds.X;
            int height = (int)_bounds.Y;
            return new Rectangle(x, y, width, height);
        }
        #endregion

        
        #region Override Method - Update(GameTime gameTime)
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            if (this.IsInitialized)
            {
                this.Position = _position;
                this.RelativePosition = _relativePosition;

                foreach (Action a in _actions)
                {
                    a.Check(Mouse.GetState(), Keyboard.GetState());
                }

                base.Update(gameTime);
            }
        }
        #endregion

        // IAction Member
        #region Interface - IAction Members
        public void Execute(string command)
        {
            if (this.IsInitialized)
            {
                ExecuteCommand(command);
            }
        }
        #endregion
        // IScroll Member
        #region Interface - IScroll Members
        public void Scroll(IScrollClass.ScrollDirection direction)
        {
            DoScroll(direction);
        }
        #endregion


        #region Virtual Method - DoScroll(IScrollClass.ScrollDirection direction)
        public virtual void DoScroll(IScrollClass.ScrollDirection direction)
        {
            Console.WriteLine("Default: " + this.GetType().Name + " does not implement any scroll effect!");
        }
        #endregion

        #region Virtual Method - ExecuteCommand(string command)
        public virtual void ExecuteCommand(string command)
        {
            if (command.Equals("toggleTargetVisibility"))
            {
                if (this.Visible)
                {
                    this.Visible = false;
                }
                else
                {
                    this.Visible = true;
                }
            }
            else if (command.Equals("focus"))
            {

            }
            else if (command.Equals("unfocus"))
            {

            }
        }
        #endregion

        #region Virtual Method - Draw(GameTime gameTime, SpriteBatch sprite)
        public virtual void Draw(GameTime gameTime, SpriteBatch sprite)
        {
            if (this.IsInitialized)
            {
                foreach (InterfaceObject obj in _ios)
                {
                    obj.InstallInterface();
                }

                foreach (TextureObject textureObj in _textureObjs)
                {
                    textureObj.Draw(sprite);
                }

                foreach (TextObject textObj in _textObjs)
                {
                    textObj.Draw(sprite);
                }
            }
        }
        #endregion

        #region Virtual Method - Rescale(Vector2 bounds)
        public virtual void Rescale(Vector2 bounds)
        { }
        #endregion 
    }
}